<template>
	<el-dialog
	  title="裁切封面"
	  :visible.sync="show"
	  width="1000px"
	  :before-close="handleClose"
	  :close-on-click-modal="false"
	  :close-on-press-escape="false"
	>
	  <div class="cropper-content">
		<div class="cropper-box">
		  <div class="cropper">
			<vue-cropper
			  ref="cropper"
			  :img="option.img"
			  :output-size="option.outputSize"
			  :info="option.info"
			  :can-scale="option.canScale"
			  :auto-crop="option.autoCrop"
			  :auto-crop-width="option.autoCropWidth"
			  :auto-crop-height="option.autoCropHeight"
			  :fixed="option.fixed"
			  :fixed-number="option.fixedNumber"
			  :full="option.full"
			  :fixed-box="option.fixedBox"
			  :can-move="option.canMove"
			  :can-move-box="option.canMoveBox"
			  :original="option.original"
			  :center-box="option.centerBox"
			  :height="option.height"
			  :info-true="option.infoTrue"
			  :max-img-size="option.maxImgSize"
			  :enlarge="option.enlarge"
			  :mode="option.mode"
			  :limit-min-size="option.limitMinSize"
			  @realTime="realTime"
			/>
		  </div>
		</div>
		<!--预览效果图-->
		<div class="show-preview">
		  <div :style="previews.div" class="preview">
			<img ref="previews" :src="previews.url" :style="previews.img">
		  </div>
		</div>
	  </div>
	  <div class="mt-20">
		<el-button icon="el-icon-plus" @click="scaleBigger">放大</el-button>
		<el-button icon="el-icon-minus" @click="scaleSmaller">缩小</el-button>
		<el-button icon="el-icon-refresh-left" @click="reload">重置大小</el-button>
	  </div>
   
	  <span slot="footer" class="dialog-footer">
		<el-button @click="handleClose">取 消</el-button>
		<el-button type="primary" @click="onSubmit">确 定</el-button>
	  </span>
	</el-dialog>
  </template>
  <script>
import { VueCropper } from 'vue-cropper'
export default {
  name: 'CropperImage',
  components: {
    VueCropper
  },
  data() {
    return {
      show: false,
      previews: {},
      option: {
        img: '', // 裁剪图片的地址
        outputSize: 1, // 裁剪生成图片的质量(可选0.1 - 1)
        outputType: 'jpeg', // 裁剪生成图片的格式（jpeg || png || webp）
        info: false, // 图片大小信息
        canScale: true, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        autoCropWidth: 300, // 默认生成截图框宽度
        autoCropHeight: 300, // 默认生成截图框高度
        fixed: true, // 是否开启截图框宽高固定比例
        fixedNumber: [1, 1], // 截图框的宽高比例
        full: false, // false按原比例裁切图片，不失真
        fixedBox: false, // 固定截图框大小，不允许改变
        canMove: true, // 上传图片是否可以移动
        canMoveBox: true, // 截图框能否拖动
        original: true, // 上传图片按照原始比例渲染
        centerBox: true, // 截图框是否被限制在图片里面
        height: true, // 是否按照设备的dpr 输出等比例图片
        infoTrue: false, // true为展示真实输出图片宽高，false展示看到的截图框宽高
        maxImgSize: 3000, // 限制图片最大宽度和高度
        enlarge: 1, // 图片根据截图框输出比例倍数
        mode: '550px 400px', // 图片默认渲染方式
        limitMinSize: [108, 108], // 裁剪框限制最小区域
        minCropBoxWidth: 108, // 设置最小裁切框宽度
        minCropBoxHeight: 108 // 设置最小裁切框高度
      },
      file: null,
      form: {}
    }
  },
  methods: {
    // 展示裁剪弹窗
    handleOpen(val, obj, form) {
      this.option = { ...this.option, ...obj }
      this.file = val
      this.form = form
      this.show = true
      this.option.img = URL.createObjectURL(val.raw)
      const reader = new FileReader()
      reader.readAsDataURL(val.raw)
    },
    // 关闭弹窗
    handleClose() {
      this.show = false
    },
    // 实时预览函数
    realTime(data) {
      this.previews = data
    },
    // 缩放图片
    resizeBlob(blob, desiredWidth, desiredHeight) {
      return new Promise((resolve, reject) => {
        const img = new Image()
        img.onload = () => {
          const canvas = document.createElement('canvas')
          const ctx = canvas.getContext('2d')
 
          // 计算缩放比例
          const scaleX = desiredWidth / img.width
          const scaleY = desiredHeight / img.height
          const scale = Math.min(scaleX, scaleY)
 
          // 设置 Canvas 的宽度和高度
          canvas.width = desiredWidth
          canvas.height = desiredHeight
 
          // 绘制图片到 Canvas 上，并进行缩放
          ctx.drawImage(img, 0, 0, img.width * scale, img.height * scale)
 
          // 将 Canvas 中的图像转换为 Blob 对象
          canvas.toBlob((resizedBlob) => {
            resolve(resizedBlob)
          }, blob.type)
        }
 
        img.onerror = (error) => {
          reject(error)
        }
 
        img.src = URL.createObjectURL(blob)
      })
    },
    // 确定
    onSubmit() {
      // 获取截图的base64
      this.$refs.cropper.getCropBlob(async(data) => {
        const originalBlob = data // 原始 Blob 对象
        const desiredWidth = this.form.sizeWidth // 所需的宽度
        const desiredHeight = this.form.sizeHeight // 所需的高度
        if (this.form.type == 'fixed') {
          // 如果是需要固定宽高的图片，直接调用方法缩放图片
          this.handleResizeBlob(originalBlob, desiredWidth, desiredHeight)
        } else if (this.form.type == 'max') {
          // 如果是需要不超过xxx宽高的图片，先做判断
          var blob = new Blob([data], { type: 'image/jpeg' })
          var img = new Image()
          var url = URL.createObjectURL(blob)
          img.src = url
          const _this = this
          img.onload = function() {
            // 获取图像的宽度和高度
            var width = img.width
            var height = img.height
 
            if (width <= desiredWidth && height <= desiredHeight) {
              // 如果裁剪完未超过限制，则直接去上传
              var result = new File([data], `头像${(new Date()).getTime()}.jpeg`, { type: 'image/jpeg', lastModified: Date.now() })
              _this.handleClose()
              _this.$emit('handleUploadSuccess', result)
            } else {
              // 如果裁剪完超过限制，则调用方法缩放图片
              _this.handleResizeBlob(originalBlob, desiredWidth, desiredHeight)
            }
            // 清理 URL 对象
            URL.revokeObjectURL(url)
          }
        }
      })
    },
    handleResizeBlob(originalBlob, desiredWidth, desiredHeight) {
      this.resizeBlob(originalBlob, desiredWidth, desiredHeight)
        .then((resizedBlob) => {
          // 在此处使用缩放后的 Blob 对象
          var result = new File([resizedBlob], `头像${(new Date()).getTime()}.jpeg`, { type: 'image/jpeg', lastModified: Date.now() })
          this.handleClose()
          this.$emit('handleUploadSuccess', result)
        })
        .catch((error) => {
          console.error('Error resizing Blob:', error)
        })
    },
    // 放大
    scaleBigger() {
      this.$refs.cropper.changeScale(1)
    },
    // 缩小
    scaleSmaller() {
      this.$refs.cropper.changeScale(-1)
    },
    // 重置大小
    reload() {
      this.$refs.cropper.reload()
    }
  }
}
</script>
<style lang="scss" scoped>
.cropper-content{
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  .cropper-box{
    width: 550px;
    .cropper{
      width: auto;
      height: 400px;
    }
  }
 
  .show-preview{
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
    .preview{
      overflow: hidden;
      border:1px solid #67c23a;
      background: #cccccc;
    }
  }
}
.footer-btn{
  margin-top: 30px;
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  .scope-btn{
    display: flex;
    display: -webkit-flex;
    justify-content: space-between;
    padding-right: 10px;
  }
  .upload-btn{
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
  }
  .btn {
    outline: none;
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    text-align: center;
    -webkit-box-sizing: border-box;
    -webkit-appearance: none;
    box-sizing: border-box;
    outline: 0;
    -webkit-transition: .1s;
    transition: .1s;
    font-weight: 500;
    padding: 8px 15px;
    font-size: 12px;
    border-radius: 3px;
    color: #fff;
    background-color: #409EFF;
    border-color: #409EFF;
    margin-right: 10px;
  }
}
</style>